package com.lzy.config;

import com.lzy.filters.JwtAuthenticationTokenFilter;
import com.lzy.handle.security.MyAuthenticationEntryPoint;
import com.lzy.handle.security.MyLogoutSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/**
 * @author lyw
 * @Date 2023/1/30-下午4:24
 */

@Configuration
// 自定义校验
//@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  /**
   * 自定义用户认证逻辑
   */
  @Autowired
  private UserDetailsService userDetailsService;

  /**
   * 认证失败处理类
   */
  @Autowired
  private MyAuthenticationEntryPoint unauthorizedHandler;

  @Autowired
  private MyLogoutSuccessHandler logoutSuccessHandler;

  @Autowired
  private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

  /**
   * 解决 无法直接注入 AuthenticationManager
   */
  @Bean
  @Override
  public AuthenticationManager authenticationManagerBean() throws Exception
  {
    return super.authenticationManagerBean();
  }

  /*@Bean
  public CorsConfigurationSource corsConfigurationSource() {
    CorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

    CorsConfiguration corsConfiguration = new CorsConfiguration();
    // 同源配置，*表示任何请求都视为同源，若需指定ip和端口可以改为如“localhost：8080”，多个以“，”分隔；
    corsConfiguration.addAllowedOrigin("*");
    // header，允许哪些header，本案中使用的是token，此处可将*替换为token；
    corsConfiguration.addAllowedHeader("*");
    // 允许的请求方法，PSOT、GET等
    corsConfiguration.addAllowedMethod("*");
    // 配置允许跨域访问的url
    ((UrlBasedCorsConfigurationSource) source).registerCorsConfiguration("/**",corsConfiguration);
    return source;
  }*/

  @Bean
  public CorsFilter corsFilter() {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    // 设置访问源地址
    config.addAllowedOriginPattern("*");
    // 设置访问源请求头
    config.addAllowedHeader("*");
    // 设置访问源请求方法
    config.addAllowedMethod("*");
    // 有效期 1800秒
    config.setMaxAge(1800L);

    // 添加映射路径，拦截一切请求
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);

    // 返回新的CorsFilter
    return new CorsFilter(source);
  }

  @Override
  protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
            // CSRF禁用，因为不使用session
            .csrf().disable()
            // 认证失败处理类
            .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
            // 基于token，所以不需要session
//            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            // 过滤请求
            .authorizeRequests()
            // 对于登录login 注册register 验证码captchaImage 允许匿名访问
            .antMatchers("/login", "/test", "/captchaImage").permitAll()
            .antMatchers("/doc.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**", "/avatar/**").permitAll()
            .antMatchers(HttpMethod.OPTIONS,"/**").permitAll()
            // 除上面外的所有请求全部需要鉴权认证
            .anyRequest()
            .authenticated()
            .and()
            .formLogin().disable()
            .logout()
            .logoutUrl("/logout")
            // 跳转页面
            .logoutSuccessHandler(logoutSuccessHandler)
            .and()
            .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    ;
  }

  /**
   * 强散列哈希加密实现
   */
  @Bean
  public BCryptPasswordEncoder bCryptPasswordEncoder() {
    return new BCryptPasswordEncoder();
  }

  /**
   * 身份认证接口
   */
  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
  }
}

/**
 @Configuration
 @EnableWebSecurity
 @EnableGlobalMethodSecurity(prePostEnabled = true) //开启权限注解,默认是关闭的
 public class SecurityConfig extends WebSecurityConfigurerAdapter {

 @Autowired
 private MySuccessHander mySuccessHander;
 @Autowired
 private MyFailureHander myFailureHander;
 @Autowired
 private UserAuthAccessDeniedHandler userAuthAccessDeniedHandler;
 @Autowired
 private UserLoginFailureHandler userLoginFailureHandler;
@Bean
public PasswordEncoder createPwdEncoder(){
  return new BCryptPasswordEncoder();
}


   /*   加上无响应(不会进行登录)  不要加
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

    }

   * 配置拦截请求资源
  @Override
  protected void configure(HttpSecurity http) throws Exception {

       /*
        //对根目录下的所有子目录进行拦截认证  默认方式 /**
        http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and()
                .formLogin(); //默认的认证方式,表单认证
//        .httpBasic();   //使用浏览器提供的表单

    //对根目录下的所有子目录进行拦截认证  默认方式
    http.authorizeRequests()
            .antMatchers("/static/**").permitAll()  //放行静态资源
            .antMatchers("/static/script/**").permitAll()  //放行静态资源(无效 不知道原因)
            .antMatchers("/initialPage","/toSession").permitAll()    ///initialPage permitAll() 该initialPage页面下不被拦截(放行)
            .antMatchers("/login").permitAll()    ///login permitAll() login 登录页不被拦截(放行)
            .antMatchers("/toLogin").permitAll()    ///toLogin permitAll() toLogin 登录页不被拦截(放行)
//                .antMatchers("/static/**").permitAll()
            .antMatchers("/regist").permitAll()    ///regist permitAll() regist 登录页不被拦截(放行)
            .antMatchers(" /favicon.ico").permitAll()    //放行  不需要认证

            .antMatchers("/**").fullyAuthenticated();  // /** fullyAuthenticated()所有的都被拦截  拦截所有
//        .httpBasic();   //使用浏览器提供的表单

    http.csrf().disable().cors();   //关闭csrf功能，登出失败可能存在的原因 以及登录失败(不请求action)的原因 并且开启跨域
//          http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());  springSecurity自动往浏览器写入token


    http.formLogin().loginPage("/toLogin").  //默认的认证方式 表单认证 (提交的时候url与loginPage方法中的参数保持一致也可以成功)
//                loginProcessingUrl("/login");
        loginProcessingUrl("/login").      //提交的时候url与loginProcessingUrl方法中的参数保持一致(成功)
            successHandler(mySuccessHander).failureHandler(userLoginFailureHandler);
//                .usernameParameter("user").passwordParameter("pwd");  //自定义用户名和密码的参数名

    http.logout().logoutSuccessUrl("/toLogin");   //注销功能 logoutSuccessUrl注销成功后默认跳转页面(controller控制器)
//        http.sessionManagement().sessionFixation().changeSessionId(); //默认更改JsessionId
//        http.sessionManagement().maximumSessions(1).maxSessionsPreventsLogin(true).and().invalidSessionUrl("/toSession");
//        http.sessionManagement().maximumSessions(1).maxSessionsPreventsLogin(true).and().invalidSessionUrl("/toSession");
    // 并发session控制  一个人用户在一台服务器上同时有多少个session
    //maxSessionsPreventsLogin(true) 如果达到了最大session数,不允许新的session数再次登录
    //.invalidSessionUrl("/toLogin") session失效后跳转到的url

    //配置没有权限自定义处理器
//        http.exceptionHandling().accessDeniedHandler(userAuthAccessDeniedHandler);
    //记住我功能  cookie默认保存两周
//        http.rememberMe().rememberMeParameter("");
  }
}
 */
